﻿// Copyright (c) 2010 2011 2012 唐锐(also tr0217)
// mailto:tr0217@163.com
// The earliest release time: 2010-12-18
// Last modification time:
// Accompanying files of necessity:
//        * ToolStripContainerForm.cs
//        * ToolStripPanelEx.cs
//        * ExistingComponentChooser.cs
//        * ExistingComponentChooser.Designer.cs
//        * ExistingComponentChooser.resx
//        * ToolStripPanelCollectionEditor.cs
//
// This file and the accompanying files of this project may be freely used provided the following
// conditions are met:
//        * This copyright statement is not removed or modified.
//        * The code is not sold in uncompiled form.  (Release as a compiled binary which is part
//          of an application is fine)
//        * The design, code, or compiled binaries are not "Re-branded".
//        
// Optional:
//        * Redistributions in binary form must reproduce the above copyright notice.
//        * I receive a fully licensed copy of the product (regardless of whether the product is
//          is free, shrinkwrap, or commercial).  This is optional, though if you release products
//          which use code I've contributed to, I would appreciate a fully licensed copy.
//
// In addition, you may not:
//        * Publicly release modified versions of the code or publicly release works derived from
//          the code without express written authorization.
//
// NO WARRANTY:
//        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//        ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
//        WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
//        IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
//        INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
//        NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
//        OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
//        WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
//        ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
//        OF SUCH DAMAGE.
//

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace TR0217.ControlEx
{
    [ToolboxBitmap(typeof(FloatableToolStrip), "FloatableToolStrip.bmp")]
    public class FloatableToolStrip : ToolStrip
    {
        private ToolStripContainerForm _toolStripContainerForm = null;
        private Control _originalParent = null;
        private bool _aboutToFloat = false;
        private bool _isFloating = false;
        private bool _parentChanged = false;

        private List<ToolStripPanelEx> _toolStripPanelExList = new List<ToolStripPanelEx>();


        internal Control OriginalParent
        {
            get { return _originalParent; }
        }

        [Editor(typeof(ToolStripPanelCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public List<ToolStripPanelEx> ToolStripPanelExList
        {
            get { return _toolStripPanelExList; }
            set { _toolStripPanelExList = value; }
        }

        public bool IsFloating
        {
            get { return _isFloating; }
        }

        public new bool Visible
        {
            get { return base.Visible; }
            set
            {
                if (_isFloating)
                    _toolStripContainerForm.Visible = value;
                else
                    base.Visible = value;
            }
        }

        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);
            if (base.Parent != null)
            {
                if (!(base.Parent is ToolStripContainerForm))
                {
                    _originalParent = this.Parent;
                    if (_aboutToFloat)
                        _parentChanged = true;
                }
            }
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            this.Focus();
        }

        protected override void OnMouseDown(MouseEventArgs mea)
        {
            base.OnMouseDown(mea);
            if (!_isFloating && base.GripRectangle.Contains(mea.Location))
                _aboutToFloat = true;
        }

        protected override void OnMouseUp(MouseEventArgs mea)
        {
            base.OnMouseUp(mea);
            if (_parentChanged)
            {
                _parentChanged = false;
                _aboutToFloat = false;
                return;
            }
                
            Point p = this.PointToScreen(mea.Location);
            Point p1 = _originalParent.PointToClient(p);
            if (_aboutToFloat && !_originalParent.ClientRectangle.Contains(p1))
            {
                if (_toolStripContainerForm == null)
                {
                    _toolStripContainerForm = new ToolStripContainerForm();
                    _toolStripContainerForm.NCLBUTTONDBLCLK += new EventHandler(_toolStripContainerForm_NCLBUTTONDBLCLK);
                    _toolStripContainerForm.LocationChanged += new EventHandler(_toolStripContainerForm_LocationChanged);
                    _toolStripContainerForm.FormClosing += new FormClosingEventHandler(_toolStripContainerForm_FormClosing);
                }
                _originalParent.Controls.Remove(this);
                _toolStripContainerForm.ToolStrip = this;
                _toolStripContainerForm.Location = p;
                _toolStripContainerForm.Show(base.Parent.Parent);
                
                _aboutToFloat = false;
                _isFloating = true;
            }
        }

        [DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern void GetCursorPos(out Point pt);

        void _toolStripContainerForm_LocationChanged(object sender, EventArgs e)
        {
            Point pt;
            if(_parentChanged )
                _parentChanged = false;
            GetCursorPos(out pt);


            foreach (ToolStripPanelEx tspe in _toolStripPanelExList)
            {
                if (tspe.ActiveRect.Contains(tspe.PointToClient(pt)))
                {
                    _toolStripContainerForm.Controls.Remove(this);
                    tspe.SuspendLayout();
                    base.Dock = DockStyle.None;
                    base.Anchor = AnchorStyles.Top | AnchorStyles.Left;
                    tspe.Controls.Add(this);
                    tspe.ResumeLayout();
                    _toolStripContainerForm.Hide();
                    _isFloating = false;
                    _parentChanged = false;

                    if (_originalParent.Parent != null)
                        _originalParent.Parent.Focus();
                    else
                        _originalParent.Focus();
                    return;
                }
            }
        }

        void _toolStripContainerForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
                _toolStripContainerForm.Visible = false;
                base.OnVisibleChanged(new EventArgs());
            }
        }

        void _toolStripContainerForm_NCLBUTTONDBLCLK(object sender, EventArgs e)
        {
            _toolStripContainerForm.Controls.Remove(this);
            _toolStripContainerForm.Visible = false;
            _originalParent.SuspendLayout();
            base.Dock = DockStyle.None;
            base.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            //ToolStripPanel tsp = _originalParent as ToolStripPanel;
            //if (tsp != null)
            //{
            //    if (tsp.Orientation == System.Windows.Forms.Orientation.Horizontal)
            //        base.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow;
            //    else base.LayoutStyle = ToolStripLayoutStyle.VerticalStackWithOverflow;

            //}
            //else
            //    base.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow;
            _originalParent.Controls.Add(this);
            _originalParent.ResumeLayout();
            _isFloating = false;
        }
    }
}
